#include "GLVertexArray.h"
#include "GL.h"

#include <Rz/Graphics/Render/IRenderDevice.h>

namespace Rz { namespace Graphics { namespace Render { namespace Libraries { namespace OpenGL {

GLVertexArray::GLVertexArray(IRenderDevice* renderDevice)
	: _vertexArrayHandle(static_cast<GLuint>(-1))
	, _isDirty(true)
{
	this->SetRenderDevice(renderDevice);
	this->SetVertexBuffer(renderDevice->CreateVertexBuffer());
	this->SetIndexBuffer(renderDevice->CreateIndexBuffer());
	_vertexArrayHandle = GL::GenVertexArray();
}

GLVertexArray::GLVertexArray(IRenderDevice* renderDevice, IVertexBuffer* vertexBuffer, IIndexBuffer* indexBuffer)
	: _vertexArrayHandle(static_cast<GLuint>(-1))
	, _isDirty(false)
{
	this->SetRenderDevice(renderDevice);
	this->SetVertexBuffer(vertexBuffer);
	this->SetIndexBuffer(indexBuffer);
	_vertexArrayHandle = GL::GenVertexArray();
}

GLVertexArray::~GLVertexArray()
{
	GL::DeleteVertexArray(_vertexArrayHandle);
}

void GLVertexArray::Rebuild()
{
	this->Bind();

	// we must call members directly, because Bind is non-const method and it would produce stack overflow due to recursion,
	// because non-const members Get*Buffer set _isDirty flag to true
	_vertexBuffer->Bind();
	_indexBuffer->Bind();

	this->Unbind();
}

bool GLVertexArray::IsDirty() const
{
	return _isDirty;
}

// override non-const methods, because it could be used for setting new buffers
IVertexBuffer* GLVertexArray::GetVertexBuffer()
{
	_isDirty = true;
	return IVertexArray::GetVertexBuffer();
}

IIndexBuffer* GLVertexArray::GetIndexBuffer()
{ 
	_isDirty = true;
	return IVertexArray::GetIndexBuffer();
}

void GLVertexArray::SetVertexBuffer(IVertexBuffer* vertexBuffer)
{
	_isDirty = true;
	IVertexArray::SetVertexBuffer(vertexBuffer);
}

void GLVertexArray::SetIndexBuffer(IIndexBuffer* indexBuffer)
{
	_isDirty = true;
	IVertexArray::SetIndexBuffer(indexBuffer);
}

// IDeviceResource
void GLVertexArray::Bind()
{
	if (_isDirty)
	{
		_isDirty = false;
		this->Rebuild();
	}

	GL::BindVertexArray(_vertexArrayHandle);
}

void GLVertexArray::Unbind()
{
	GL::BindVertexArray(0);
}

} } } } }
